using Engine;
using Engine.Graphics;
using System;
using System.Collections.Generic;

namespace Game
{
    public class LightbulbBlock : MountedElectricElementBlock, IPaintableBlock
    {
        public const int Index = 139;

        public BlockMesh m_standaloneBulbBlockMesh = new BlockMesh();

        public BlockMesh m_standaloneSidesBlockMesh = new BlockMesh();

        public BlockMesh[] m_bulbBlockMeshes = new BlockMesh[6];

        public BlockMesh[] m_bulbBlockMeshesLit = new BlockMesh[6];

        public BlockMesh[] m_sidesBlockMeshes = new BlockMesh[6];

        public BoundingBox[][] m_collisionBoxes = new BoundingBox[6][];
        public static new string fName = "LightbulbBlock";
        public Color m_copperColor = new Color(118, 56, 32);

        public override void Initialize()
        {
            Model model = ContentManager.Get<Model>("Models/Lightbulbs");
            Matrix boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh("Top").ParentBone);
            Matrix boneAbsoluteTransform2 = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh("Sides").ParentBone);
            for (int i = 0; i < 6; i++)
            {
                Matrix m = (i >= 4) ? ((i != 4) ? (Matrix.CreateRotationX((float)Math.PI) * Matrix.CreateTranslation(0.5f, 1f, 0.5f)) : Matrix.CreateTranslation(0.5f, 0f, 0.5f)) : (Matrix.CreateRotationX((float)Math.PI / 2f) * Matrix.CreateTranslation(0f, 0f, -0.5f) * Matrix.CreateRotationY(i * (float)Math.PI / 2f) * Matrix.CreateTranslation(0.5f, 0.5f, 0.5f));
                m_bulbBlockMeshes[i] = new BlockMesh();
                m_bulbBlockMeshes[i].AppendModelMeshPart(model.FindMesh("Top").MeshParts[0], boneAbsoluteTransform * m, makeEmissive: false, flipWindingOrder: false, doubleSided: false, flipNormals: false, Color.White);
                m_bulbBlockMeshes[i].TransformTextureCoordinates(Matrix.CreateTranslation(0.1875f, 0.25f, 0f));
                m_bulbBlockMeshesLit[i] = new BlockMesh();
                m_bulbBlockMeshesLit[i].AppendModelMeshPart(model.FindMesh("Top").MeshParts[0], boneAbsoluteTransform * m, makeEmissive: true, flipWindingOrder: false, doubleSided: false, flipNormals: false, new Color(255, 255, 230));
                m_bulbBlockMeshesLit[i].TransformTextureCoordinates(Matrix.CreateTranslation(0.9375f, 0f, 0f));
                m_sidesBlockMeshes[i] = new BlockMesh();
                m_sidesBlockMeshes[i].AppendModelMeshPart(model.FindMesh("Sides").MeshParts[0], boneAbsoluteTransform2 * m, makeEmissive: false, flipWindingOrder: false, doubleSided: true, flipNormals: false, Color.White);
                m_sidesBlockMeshes[i].TransformTextureCoordinates(Matrix.CreateTranslation(0.9375f, 0.1875f, 0f));
                m_collisionBoxes[i] = new BoundingBox[1]
                {
                    m_sidesBlockMeshes[i].CalculateBoundingBox()
                };
            }
            Matrix m2 = Matrix.CreateRotationY(-(float)Math.PI / 2f) * Matrix.CreateRotationZ((float)Math.PI / 2f);
            m_standaloneBulbBlockMesh.AppendModelMeshPart(model.FindMesh("Top").MeshParts[0], boneAbsoluteTransform * m2, makeEmissive: false, flipWindingOrder: false, doubleSided: true, flipNormals: false, Color.White);
            m_standaloneBulbBlockMesh.TransformTextureCoordinates(Matrix.CreateTranslation(0.1875f, 0.25f, 0f));
            m_standaloneSidesBlockMesh.AppendModelMeshPart(model.FindMesh("Sides").MeshParts[0], boneAbsoluteTransform2 * m2, makeEmissive: false, flipWindingOrder: false, doubleSided: true, flipNormals: false, Color.White);
            m_standaloneSidesBlockMesh.TransformTextureCoordinates(Matrix.CreateTranslation(0.9375f, 0.1875f, 0f));
        }

        public override IEnumerable<int> GetCreativeValues()
        {
            yield return Terrain.MakeBlockValue(139);
            int i = 0;
            while (i < 16)
            {
                yield return Terrain.MakeBlockValue(139, 0, SetColor(0, i));
                int num = i + 1;
                i = num;
            }
        }

        public override string GetDisplayName(SubsystemTerrain subsystemTerrain, int value)
        {
            int? color = GetColor(Terrain.ExtractData(value));
            return SubsystemPalette.GetName(subsystemTerrain, color, LanguageControl.Get(fName, 1));
        }

        public override string GetCategory(int value)
        {
            if (!GetColor(Terrain.ExtractData(value)).HasValue)
            {
                return base.GetCategory(value);
            }
            return "Painted";
        }

        public override int GetFace(int value)
        {
            return GetMountingFace(Terrain.ExtractData(value));
        }

        public override int GetEmittedLightAmount(int value)
        {
            return GetLightIntensity(Terrain.ExtractData(value));
        }

        public override int GetShadowStrength(int value)
        {
            int lightIntensity = GetLightIntensity(Terrain.ExtractData(value));
            return DefaultShadowStrength - 10 * lightIntensity;
        }

        public override BlockPlacementData GetPlacementValue(SubsystemTerrain subsystemTerrain, ComponentMiner componentMiner, int value, TerrainRaycastResult raycastResult)
        {
            BlockPlacementData result = default;
            result.Value = Terrain.MakeBlockValue(139, 0, SetMountingFace(Terrain.ExtractData(value), raycastResult.CellFace.Face));
            result.CellFace = raycastResult.CellFace;
            return result;
        }

        public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
        {
            int? color = GetColor(Terrain.ExtractData(oldValue));
            dropValues.Add(new BlockDropValue
            {
                Value = Terrain.MakeBlockValue(139, 0, SetColor(0, color)),
                Count = 1
            });
            showDebris = true;
        }

        public override BoundingBox[] GetCustomCollisionBoxes(SubsystemTerrain terrain, int value)
        {
            int mountingFace = GetMountingFace(Terrain.ExtractData(value));
            if (mountingFace >= m_collisionBoxes.Length)
            {
                return null;
            }
            return m_collisionBoxes[mountingFace];
        }

        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
        {
            int data = Terrain.ExtractData(value);
            int mountingFace = GetMountingFace(data);
            int lightIntensity = GetLightIntensity(data);
            int? color = GetColor(data);
            Color color2 = color.HasValue ? SubsystemPalette.GetColor(generator, color) : m_copperColor;
            if (mountingFace < m_bulbBlockMeshes.Length)
            {
                if (lightIntensity <= 0)
                {
                    generator.GenerateMeshVertices(this, x, y, z, m_bulbBlockMeshes[mountingFace], Color.White, null, geometry.SubsetAlphaTest);
                }
                else
                {
                    byte r = (byte)(195 + lightIntensity * 4);
                    byte g = (byte)(180 + lightIntensity * 5);
                    byte b = (byte)(165 + lightIntensity * 6);
                    generator.GenerateMeshVertices(this, x, y, z, m_bulbBlockMeshesLit[mountingFace], new Color(r, g, b), null, geometry.SubsetOpaque);
                }
                generator.GenerateMeshVertices(this, x, y, z, m_sidesBlockMeshes[mountingFace], color2, null, geometry.SubsetOpaque);
                generator.GenerateWireVertices(value, x, y, z, mountingFace, 0.875f, Vector2.Zero, geometry.SubsetOpaque);
            }
        }

        public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
        {
            int? color2 = GetColor(Terrain.ExtractData(value));
            Color c = color2.HasValue ? SubsystemPalette.GetColor(environmentData, color2) : m_copperColor;
            BlocksManager.DrawMeshBlock(primitivesRenderer, m_standaloneSidesBlockMesh, color * c, 2f * size, ref matrix, environmentData);
            BlocksManager.DrawMeshBlock(primitivesRenderer, m_standaloneBulbBlockMesh, color, 2f * size, ref matrix, environmentData);
        }

        public int? GetPaintColor(int value)
        {
            return GetColor(Terrain.ExtractData(value));
        }

        public int Paint(SubsystemTerrain subsystemTerrain, int value, int? color)
        {
            int data = Terrain.ExtractData(value);
            return Terrain.ReplaceData(value, SetColor(data, color));
        }

        public override ElectricElement CreateElectricElement(SubsystemElectricity subsystemElectricity, int value, int x, int y, int z)
        {
            return new LightBulbElectricElement(subsystemElectricity, new CellFace(x, y, z, GetFace(value)), value);
        }

        public override ElectricConnectorType? GetConnectorType(SubsystemTerrain terrain, int value, int face, int connectorFace, int x, int y, int z)
        {
            int face2 = GetFace(value);
            if (face == face2 && SubsystemElectricity.GetConnectorDirection(face2, 0, connectorFace).HasValue)
            {
                return ElectricConnectorType.Input;
            }
            return null;
        }

        public static int GetMountingFace(int data)
        {
            return data & 7;
        }

        public static int SetMountingFace(int data, int face)
        {
            return (data & -8) | (face & 7);
        }

        public static int GetLightIntensity(int data)
        {
            return (data >> 3) & 0xF;
        }

        public static int SetLightIntensity(int data, int intensity)
        {
            return (data & -121) | ((intensity & 0xF) << 3);
        }

        public static int? GetColor(int data)
        {
            if ((data & 0x80) != 0)
            {
                return (data >> 8) & 0xF;
            }
            return null;
        }

        public static int SetColor(int data, int? color)
        {
            if (color.HasValue)
            {
                return (data & -3969) | 0x80 | ((color.Value & 0xF) << 8);
            }
            return data & -3969;
        }
    }
}
